package com.zs.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zs.blog.converter.ArticleConverter;
import com.zs.blog.converter.CategoryConverter;
import com.zs.blog.dao.*;
import com.zs.blog.exception.BusinessException;
import com.zs.blog.model.dto.ArticleCategoryDTO;
import com.zs.blog.model.dto.ArticleDTO;
import com.zs.blog.model.dto.ArticleTagDTO;
import com.zs.blog.model.entity.*;
import com.zs.blog.model.vo.*;
import com.zs.blog.service.IArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import static com.zs.blog.constant.enums.SQLConstant.*;

/**
 * @Title: IArticleServiceImpl
 * @Author zs
 * @Package com.zs.blog.service.impl
 * @Date 2024/10/13 20:20
 * @description: 文章服务层实现
 */
@Service
public class IArticleServiceImpl extends ServiceImpl<IArticleMapper, Article> implements IArticleService {

    public IArticleMapper articleMapper;
    public ICategoryMapper categoryMapper;
    public ITagMapper tagMapper;
    public IArticleCategoryMapper articleCategoryMapper;
    public IArticleTagMapper articleTagMapper;

    @Autowired
    public IArticleServiceImpl(IArticleMapper articleMapper, ICategoryMapper categoryMapper, ITagMapper tagMapper, IArticleCategoryMapper articleCategoryMapper, IArticleTagMapper articleTagMapper) {
        this.articleMapper = articleMapper;
        this.categoryMapper = categoryMapper;
        this.tagMapper = tagMapper;
        this.articleCategoryMapper = articleCategoryMapper;
        this.articleTagMapper = articleTagMapper;
    }

    /**
     * 获取分页的文章列表
     *
     * @param pageNum  页码
     * @param pageSize 每页数量
     * @return
     */
    @Override
    public PageInfoVO<ArticleListVO> listArticleWithPagination(Integer pageNum, Integer pageSize) {
        // 获取到某页的文章
        LambdaQueryWrapper<Article> lqw = new LambdaQueryWrapper<>();
        IPage<Article> page = new Page<>(pageNum, pageNum);
        List<Article> articleList = articleMapper.selectList(page, lqw);

        // 遍历每一个文章，获取这个文章对应的分类与标签
        List<Article> completeArticle = new ArrayList<>();
        articleList.forEach((article) -> {
            // 获取文章对应分类
            ArticleCategoryDTO ca = categoryMapper.getCategoryByArticleId(article.getId());
            article.setCategoryName(ca.getCategoryName());

            // 获取文章对应标签
            List<ArticleTagDTO> articleTagList = tagMapper.getTagByArticleId(article.getId());
            List<String> tagList = articleTagList.stream().map(ArticleTagDTO::getTagName).toList();
            article.setTagNameList(tagList);

            completeArticle.add(article);
        });

        // 整理数据到VO
        PageInfoVO<ArticleListVO> pageInfoVO = new PageInfoVO<>();
        List<ArticleListVO> vos = ArticleConverter.INSTANCE.completeArticle2ArticleListVO(completeArticle);
        pageInfoVO.setTotal((long) vos.size());
        pageInfoVO.setItems(vos);
        return pageInfoVO;
    }

    /**
     * 发布文章
     *
     * @param articleDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publish(ArticleDTO articleDTO) {
        // 文章信息整理
        System.out.println(articleDTO);
        Article article = ArticleConverter.INSTANCE.articleDTO2Article(articleDTO);

        // 作者ID 暂设为1
        article.setUserId(1);
        System.out.println(article);
        // 对应的数据插入到对应的表中
        if (articleMapper.insertOrUpdate(article)) {
            // 插入数据后获取主键ID
            Long articleId = article.getId();

            // 分类关联表插入数据
            ArticleCategory articleCategory = new ArticleCategory();
            articleCategory.setArticleId(articleId);
            articleCategory.setCategoryId(articleDTO.getCategoryId());
            articleCategoryMapper.insertOrUpdate(articleCategory);

            // 标签关联表插入数据
            List<ArticleTag> articleTagList = new ArrayList<>();
            List<Long> tagIdList = articleDTO.getTagIdList();
            tagIdList.forEach((item) -> {
                ArticleTag articleTag = new ArticleTag();
                articleTag.setArticleId(articleId);
                articleTag.setTagId(item);
                articleTagList.add(articleTag);
            });
            articleTagMapper.insertOrUpdate(articleTagList);
        }

    }

    /**
     * 删除文章
     *
     * @param articleIdList 文章ID列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteArticle(List<Long> articleIdList) {

        int i = articleMapper.deleteByIds(articleIdList);

        if (i > 0) {
            // 根据文章ID删除文章标签表中的数据
            LambdaQueryWrapper<ArticleTag> lqwTag = new LambdaQueryWrapper<>();
            lqwTag.in(ArticleTag::getArticleId, articleIdList);
            articleTagMapper.delete(lqwTag);

            // 根据文章ID删除文章分类表中的数据
            LambdaQueryWrapper<ArticleCategory> lqwCategory = new LambdaQueryWrapper<>();
            lqwCategory.in(ArticleCategory::getArticleId, articleIdList);
            articleCategoryMapper.delete(lqwCategory);
        }
    }

    /**
     * 修改文章状态
     *
     * @param articleId    文章ID
     * @param articleState 文章状态
     */
    @Override
    public void updateArticleState(Long articleId, Integer articleState) {
        LambdaUpdateWrapper<Article> lqw = new LambdaUpdateWrapper<>();
        lqw.eq(Article::getId, articleId).set(Article::getArticleState, articleState);
        articleMapper.update(lqw);
    }

    /**
     * 修改文章置顶状态
     *
     * @param articleId 文章ID
     * @param isTop     文章置顶状态
     */
    @Override
    public void updateArticleTopState(Long articleId, Integer isTop) {
        LambdaUpdateWrapper<Article> lqw = new LambdaUpdateWrapper<>();
        lqw.eq(Article::getId, articleId).set(Article::getArticleState, isTop);
        articleMapper.update(lqw);
    }

    /**
     * 根据文章ID获取文章数据
     *
     * @param articleId 文章ID
     * @return
     */
    @Override
    public ArticleEditVO getArticleByArticleId(Long articleId) {
        if (articleId == null) {
            throw new BusinessException("文章ID为空");
        }

        Article article = articleMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new BusinessException("文章不存在");
        }

        // 查询该文章分类
        ArticleCategory articleCategory = articleCategoryMapper.selectOne(new LambdaQueryWrapper<ArticleCategory>().eq(ArticleCategory::getArticleId, articleId));
        Category category = categoryMapper.selectById(articleCategory.getCategoryId());

        // 查询该文章标签
        List<Long> tagIdList = articleTagMapper.selectList(new LambdaQueryWrapper<ArticleTag>().eq(ArticleTag::getArticleId, articleId)).stream().map(ArticleTag::getTagId).toList();

        ArticleEditVO articleEditVO = ArticleConverter.INSTANCE.article2ArticleEditVO(article);
        articleEditVO.setCategoryName(category.getCategoryName());
        articleEditVO.setTags(tagIdList);

        return articleEditVO;
    }

    /**
     * 获取随机文章列表
     *
     * @return
     */
    @Override
    public List<ArticleRandomVO> listRandomArticle() {

        // 生成随机位置
        Long max = articleMapper.selectCount(null);
        Long startPosition = ThreadLocalRandom.current().nextLong(MIN_ARTICLE_POSITION, max);

        List<Article> listRandomArticle = articleMapper.selectRandomArticle(startPosition, RANDOM_ARTICLE_COUNT);
        int size = listRandomArticle.size();
        if (size < RANDOM_ARTICLE_COUNT) {
            listRandomArticle.addAll(articleMapper.selectRandomArticle(0L, RANDOM_ARTICLE_COUNT - size));
        }

        List<ArticleRandomVO> res = ArticleConverter.INSTANCE.articleList2ArticleRandomVOList(listRandomArticle);
        return res;
    }

    /**
     * 根据文章ID获取文章详情
     *
     * @param articleId 文章ID
     * @return
     */
    @Override
    public ArticleDetailVO getArticleDetailByArticleId(Long articleId) {

        // 根据文章ID获取文章数据
        Article article = articleMapper.selectById(articleId);

        // 获取文章对应分类
        ArticleCategoryDTO articleCategory = categoryMapper.getCategoryByArticleId(articleId);
        article.setCategoryName(articleCategory.getCategoryName());

        ArticleDetailVO articleDetail = ArticleConverter.INSTANCE.article2ArticleDetailVO(article);

        // 获取文章对应标签
        // TODO
        List<TagListVO> tagList = tagMapper.listTag();
        articleDetail.setTagList(tagList);

        // 获取当前文章的上一篇文章与下一篇文章
        LambdaQueryWrapper<Article> preLqw = new LambdaQueryWrapper<>();
        preLqw.lt(Article::getId, articleId).orderByDesc(Article::getId).last(SQL_LIMIT_1);
        Article preArticle = articleMapper.selectOne(preLqw);
        // preLqw.clear();
        LambdaQueryWrapper<Article> nextLqw = new LambdaQueryWrapper<>();
        nextLqw.gt(Article::getId, articleId).orderByAsc(Article::getId).last(SQL_LIMIT_1);
        Article nextArticle = articleMapper.selectOne(nextLqw);

        articleDetail.setPreArticleId(preArticle.getId());
        articleDetail.setPreArticleTitle(preArticle.getArticleTitle());
        articleDetail.setNextArticleId(nextArticle.getId());
        articleDetail.setNextArticleTitle(nextArticle.getArticleTitle());

        return articleDetail;
    }

    /**
     * 获取推荐文章
     *
     * @return
     */
    @Override
    public List<ArticleRecommendVO> getRecommendArticle() {
        LambdaQueryWrapper<Article> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Article::getIsTop, ARTICLE_TOP).and((wrapper) -> {
            wrapper.eq(Article::getArticleState, ARTICLE_STATE_PUBLIC);
        });
        List<Article> articleList = articleMapper.selectList(lqw);

        return ArticleConverter.INSTANCE.articleList2ArticleRecommendList(articleList);
    }

    /**
     * 获取相关文章
     *
     * @param articleId  文章ID
     * @param categoryId 分类ID
     * @return
     */
    @Override
    public List<ArticleRelatedVO> getRelatedArticle(Long articleId, Long categoryId) {
        return articleMapper.listRelatedArticle(articleId, categoryId);
    }

    @Override
    //TODO 分页优化
    public List<ArticleTimelineVO> listArticleTimeline() {
        List<Article> listArticle = this.query().list();

        List<ArticleTimelineVO> articleTimelineList = ArticleConverter.INSTANCE.articleList2ArticleTimelineList(listArticle);

        return articleTimelineList;
    }
}
